home *** CD-ROM | disk | FTP | other *** search
/ AOL File Library: 2,801 to 2,900 / aol-file-protocol-4400-2801-to-2900.zip / AOLDLs / C++ Files Library / SK (Sockects) 1.4.1 r2 / SK v1.4.1 r2.sit / SK 1.4.1 r2 / SK / SK Sources / SK_UDP.cc < prev    next >
Text File  |  1994-06-13  |  19KB  |  775 lines

  1. /***************************************************************************
  2. * Copyright ⌐ 1992-1994 Matthias Neeracher and the Decision Systems Group
  3. * Permission is granted to anyone to use this software for any purpose on
  4. * any computer system, and to redistribute it freely, subject to the
  5. * following restrictions:
  6. * 1) The authors and the Decision Systems Group are not responsible for 
  7. *    the direct or indirect consequences of use of this software, no matter 
  8. *    how awful, even if they arise from defects in the software itself.
  9. *    This restriction applies to the use of this and any derived source code 
  10. *    and also to the use of all binary produced from this and any derived 
  11. *    source code.
  12. * 2) The origin and copyrights of this software must not be misrepresented, 
  13. *    either by explicit claim or by omission or alteration of copyright or
  14. *    authorship header information in this file or in any derived file.
  15. * 3) Altered or derived versions must be plainly marked as such, and must not
  16. *    be misrepresented as being the original software.
  17. * We encourage users of this software to provide feedback, bug fixes,
  18. * and enhancements to the authors for incorporation into future releases.
  19. *
  20. * ==========================================================================
  21. * FILE: SK_INET.cc
  22. * AUTHOR: Matthias Neeracher and Stephan Deibel
  23. * CREATION DATE: 12Aug92
  24. * VERSION: 13Jun94
  25. * DESCRIPTION: 
  26. *
  27. * UDP datagram sockets implementation
  28. * NOTES: 
  29. * 0) This code was derived from Matthias Neerarcher's GUSI 1.1.0 and
  30. *    the socket library written by Charlie Reiman (creiman@ncsa.uiuc.edu)
  31. *    and Tom Milligan (milligan@madhaus.utcs.utoronto.ca); Copyrights
  32. *    are subject to this origin.
  33. *
  34. * MODIFICATIONS: 
  35. * --------------------------------------------------------------------------
  36. * Date     Name      Description of modification
  37. * --------------------------------------------------------------------------
  38. * 16Aug92    MN       Split off
  39. * 25Aug92    MN       Started putting some real work in
  40. * 14Sep92    MN       select() didn't return enough goodies.
  41. * 13Jul93    SD       Port to THINK C++ 6.0
  42. * 21Jul93    SD       Subsetted to only TCP/UDP, applied DSG naming 
  43. *                    conventions and commenting guidelines, and
  44. *                    changed name to "SK" for clear distinction from
  45. *                    the GUSI code from which this was derived
  46. * 13Jun94   SD       Updated based on relevant changes to GUSI (through 1.4.1)
  47. */
  48.  
  49.  
  50. #include "SK_INET_P.hh"
  51.  
  52.  
  53. /**************************************************************************/ 
  54. /**************************************************************************/ 
  55. /* Completion procedures */
  56.  
  57.  
  58. // Need to declare all completion procedures a "C" routines and not "C++"
  59. // routines due to a bug in the THINK C++ 6.0 compiler.
  60.  
  61. extern "C" {
  62.  
  63.  
  64. /*************************************************************************** *
  65. * FUNCTION:
  66. *
  67. * udp_flush_read_ahead_done
  68. *
  69. * DESCRIPTION:
  70. *
  71. * Flush read-ahead completion procedure
  72. *
  73. * PARAMETERS:
  74. *
  75. * CSK_AnnotatedPB *        -- Parameter block associated with completed flush read ahead
  76. *
  77. */
  78.  
  79. void udp_flush_read_ahead_done(CSK_AnnotatedPB *pb)
  80. {
  81.     UDPiopb * udp = pb->UDP();
  82.  
  83.     // Check for nasty error that once plagued us (will be removed eventually)
  84.     ASSERT(udp->ioResult != inProgress);
  85. }
  86.  
  87.  
  88. /*************************************************************************** *
  89. * FUNCTION:
  90. *
  91. * udp_read_ahead_done
  92. *
  93. * DESCRIPTION:
  94. *
  95. * Read-ahead completion procedure
  96. *
  97. * PARAMETERS:
  98. *
  99. * CSK_AnnotatedPB *        -- Parameter block associated with completed read ahead
  100. *
  101. */
  102.  
  103. void udp_read_ahead_done(CSK_AnnotatedPB *pb)
  104. {
  105.     CSK_UDPSocket * sock = (CSK_UDPSocket *) pb->Owner();
  106.     UDPiopb * udp = pb->UDP();
  107.  
  108.     if (!udp->ioResult) {
  109.         sock->fReceiveBuf = udp->csParam.receive.rcvBuff;
  110.         sock->fBytesReceived = udp->csParam.receive.rcvBuffLen;
  111.     } else {
  112.         sock->fReceiveBuf = nil;
  113.         sock->fBytesReceived = 0;
  114.     }
  115.     sock->fLastAsyncErr                         = udp->ioResult;
  116.     sock->fPeerSocketAddress.sin_len             = sizeof(struct sockaddr_in);
  117.     sock->fPeerSocketAddress.sin_family         = AF_INET;
  118.     sock->fPeerSocketAddress.sin_addr.s_addr    = udp->csParam.receive.remoteHost;
  119.     sock->fPeerSocketAddress.sin_port            = udp->csParam.receive.remotePort;
  120.  
  121.     // Check for nasty error that once plagued us (will be removed eventually)
  122.     ASSERT(udp->ioResult != inProgress);
  123. }
  124.  
  125.  
  126. /*************************************************************************** *
  127. * FUNCTION:
  128. *
  129. * udp_send_done
  130. *
  131. * DESCRIPTION:
  132. *
  133. * UDP send completion procedure
  134. *
  135. * PARAMETERS:
  136. *
  137. * CSK_AnnotatedPB *        -- Parameter block associated with completed send
  138. *
  139. */
  140.  
  141. void udp_send_done(CSK_AnnotatedPB *pb)
  142. {    
  143.     UDPiopb * udp = pb->UDP();
  144.     
  145.     ((SKt_MiniWds *)udp->csParam.send.wdsPtr)->terminus    = udp->ioResult;
  146.     ((SKt_MiniWds *)udp->csParam.send.wdsPtr)->ptr        = nil;
  147.  
  148.     // Check for nasty error that once plagued us (will be removed eventually)
  149.     ASSERT(udp->ioResult != inProgress);
  150. }
  151.  
  152.  
  153. } /* extern "C" */
  154.  
  155.  
  156. /**************************************************************************/ 
  157. /**************************************************************************/ 
  158. /* CSK_UDPSocket members */
  159.  
  160.  
  161. /*************************************************************************** *
  162. * FUNCTION:
  163. *
  164. * CSK_UDPSocket::CSK_UDPSocket
  165. *
  166. * DESCRIPTION:
  167. *
  168. * Constructor for this class
  169. *
  170. */
  171.  
  172. CSK_UDPSocket::CSK_UDPSocket()
  173.     :    CSK_INETSocket()
  174. {
  175.     fSocketState = SKk_STATE_NO_STREAM;
  176. }
  177.  
  178.  
  179. /*************************************************************************** *
  180. * FUNCTION:
  181. *
  182. * CSK_UDPSocket::CSK_UDPSocket
  183. *
  184. * DESCRIPTION:
  185. *
  186. * Constructor for this class
  187. *
  188. * PARAMETERS:
  189. *
  190. * StreamPtr            -- The stream to use with this UDP socket
  191. *
  192. */
  193.  
  194. CSK_UDPSocket::CSK_UDPSocket(StreamPtr stream)
  195.     :    CSK_INETSocket(stream)
  196. {
  197.     OSErr            err;
  198.     UDPiopb *    pb;
  199.  
  200.     pb = GetPB();
  201.     pb->ioCompletion = UDPIOCompletionProc(udp_read_ahead_done);
  202.     pb->csCode = UDPRead;
  203.     pb->csParam.receive.timeOut            = 0 /* infinity */;
  204.     pb->csParam.receive.secondTimeStamp    = 0 /* must be zero */;
  205.  
  206.     /* We know that there is a read pending, so we make a synchronous call */
  207.     
  208.     err = PBControlSync(ParmBlkPtr(pb));
  209.  
  210.     // Check for nasty error that once plagued us (will be removed eventually)
  211.     ASSERT(pb->ioResult != inProgress);
  212.  
  213.     if (err != 0)
  214.         SK_TCPError(err);
  215.     
  216.     if (!pb->ioResult) {
  217.         fReceiveBuf    = pb->csParam.receive.rcvBuff;
  218.         fBytesReceived        = pb->csParam.receive.rcvBuffLen;
  219.     } else {
  220.         fReceiveBuf    = nil;
  221.         fBytesReceived        = 0;
  222.     }
  223.     fLastAsyncErr                         =    pb->ioResult;
  224.     fPeerSocketAddress.sin_len             =     sizeof(struct sockaddr_in);
  225.     fPeerSocketAddress.sin_family         =     AF_INET;
  226.     fPeerSocketAddress.sin_addr.s_addr    =    pb->csParam.receive.remoteHost;
  227.     fPeerSocketAddress.sin_port            =    pb->csParam.receive.remotePort;
  228. }
  229.  
  230.  
  231. /*************************************************************************** *
  232. * FUNCTION:
  233. *
  234. * CSK_UDPSocket::~CSK_UDPSocket
  235. *
  236. * DESCRIPTION:
  237. *
  238. * Destructor for this class
  239. *
  240. */
  241.  
  242. CSK_UDPSocket::~CSK_UDPSocket()
  243. {
  244.     UDPiopb * pb;
  245.     
  246.     if (fSocketState == SKk_STATE_NO_STREAM)
  247.         return;
  248.     
  249.     pb = GetPB();    
  250.     pb->csCode = UDPRelease;
  251.     
  252.     if (!PBControlSync(ParmBlkPtr(pb)))
  253.         DisposPtr(pb->csParam.create.rcvBuff);
  254.  
  255.     // Check for nasty error that once plagued us (will be removed eventually)
  256.     ASSERT(pb->ioResult != inProgress);
  257. }
  258.  
  259.  
  260. /*************************************************************************** *
  261. * FUNCTION:
  262. *
  263. * CSK_UDPSocket::GetPB
  264. *
  265. * DESCRIPTION:
  266. *
  267. * Get a UDP io parameter block for use with this UDP socket.  The
  268. * parameter block is obtained from the SKg_INETSockets domain object
  269. * and is set up for use specifically with this socket.
  270. *
  271. * RETURNS:
  272. *
  273. * UDPiopb *            -- The UDP io parameter block
  274. *
  275. */
  276.  
  277. UDPiopb * CSK_UDPSocket::GetPB()
  278. {
  279.     CSK_AnnotatedPB *    pb        =    SKg_INETSockets.GetPB();
  280.     pb->UDP()->ioCRefNum =    SKg_INETSockets.Driver();
  281.     pb->UDP()->udpStream    =    fStream;
  282.     
  283.     pb->SetOwner(this);
  284.     
  285.     return pb->UDP();
  286. }
  287.  
  288.  
  289. /*************************************************************************** *
  290. * FUNCTION:
  291. *
  292. * CSK_UDPSocket::Available
  293. *
  294. * DESCRIPTION:
  295. *
  296. * Return number of bytes of unread data available on this socket
  297. *
  298. * RETURNS:
  299. *
  300. * u_long        -- The number of unread bytes available
  301. *
  302. */
  303.  
  304. unsigned long CSK_UDPSocket::Available()
  305. {
  306.     return (fLastAsyncErr == inProgress) ? 0 : fBytesReceived;
  307. }
  308.  
  309.  
  310. /*************************************************************************** *
  311. * FUNCTION:
  312. *
  313. * CSK_UDPSocket::NewStream
  314. *
  315. * DESCRIPTION:
  316. *
  317. * ???
  318. *
  319. * RETURNS:
  320. *
  321. * int            -- Error value (0 = no error)
  322. *
  323. */
  324.  
  325. int CSK_UDPSocket::NewStream()
  326. {
  327.     OSErr err;
  328.     UDPiopb * pb;
  329.  
  330.     pb = GetPB();
  331.     pb->csCode = UDPCreate;
  332.     pb->csParam.create.rcvBuff = (char *)NewPtr(SKk_StreamBufferSize);
  333.     pb->csParam.create.rcvBuffLen = SKk_StreamBufferSize;
  334.     pb->csParam.create.notifyProc = NULL;
  335.     pb->csParam.create.localPort = fMySocketAddress.sin_port;
  336.     
  337.     err = PBControlSync(ParmBlkPtr(pb));
  338.  
  339.     // Check for nasty error that once plagued us (will be removed eventually)
  340.     ASSERT(pb->ioResult != inProgress);
  341.  
  342.     if (err != 0)
  343.         return SK_TCPError(err);
  344.         
  345.     fStream         = pb->udpStream;
  346.     fMySocketAddress.sin_port = pb->csParam.create.localPort;
  347.     
  348.     fSocketState     = SKk_STATE_UNCONNECTED;
  349.     fBytesReceived     = 0;
  350.     fReceiveBuf     = nil;
  351.     fLastAsyncErr    = inProgress;
  352.  
  353.     return ReadAhead();
  354. }
  355.  
  356.  
  357. /*************************************************************************** *
  358. * FUNCTION:
  359. *
  360. * CSK_UDPSocket::FlushReadAhead
  361. *
  362. * DESCRIPTION:
  363. *
  364. * Flush the read-ahead buffer for this UDP socket
  365. *
  366. * RETURNS:
  367. *
  368. * int            -- Error value (0 = no error)
  369. *
  370. */
  371.  
  372. int CSK_UDPSocket::FlushReadAhead()
  373. {
  374.     OSErr            err;
  375.     UDPiopb *    pb;
  376.  
  377.     /* flush the read-ahead buffer if its not from our new friend */
  378.     pb = GetPB();
  379.     pb->ioCompletion = UDPIOCompletionProc(udp_flush_read_ahead_done);
  380.     pb->csCode = UDPBfrReturn;
  381.     pb->csParam.receive.rcvBuff    = fReceiveBuf;
  382.     fReceiveBuf    = nil;
  383.     fBytesReceived = 0;
  384.     
  385.     err = PBControlAsync(ParmBlkPtr(pb));
  386.  
  387.     if (err != 0)
  388.         return SK_TCPError(err);
  389.     else
  390.         return 0;
  391. }
  392.  
  393.  
  394. /*************************************************************************** *
  395. * FUNCTION:
  396. *
  397. * CSK_UDPSocket::ReadAhead
  398. *
  399. * DESCRIPTION:
  400. *
  401. * Start asyncronous read-ahead on this UDP socket
  402. *
  403. * RETURNS:
  404. *
  405. * int            -- Error value (0 = no error)
  406. *
  407. */
  408.  
  409. int CSK_UDPSocket::ReadAhead()
  410. {
  411.     OSErr            err;
  412.     UDPiopb *    pb;
  413.     
  414.     pb = GetPB();
  415.     pb->ioCompletion = UDPIOCompletionProc(udp_read_ahead_done);
  416.     pb->csCode = UDPRead;
  417.     pb->csParam.receive.timeOut            = 0 /* infinity */;
  418.     pb->csParam.receive.secondTimeStamp    = 0 /* must be zero */;
  419.     fLastAsyncErr = 1;
  420.     
  421.     err = PBControlAsync(ParmBlkPtr(pb));
  422.     if (err != 0)
  423.         return SK_TCPError(fLastAsyncErr = err);
  424.  
  425.     return 0;
  426. }
  427.  
  428. /*************************************************************************** *
  429. * FUNCTION:
  430. *
  431. * CSK_UDPSocket::getsockname
  432. *
  433. * DESCRIPTION:
  434. *
  435. * Returns the current name for the given socket.
  436. *
  437. * PARAMETERS:
  438. *
  439. * void *        -- Buffer space for returned name
  440. * int *            -- Buffer space for returned name length (should contain
  441. *                  maximum allowable return length initially)
  442. *
  443. * RETURNS
  444. *
  445. * int            -- 0 upon success; -1 upon failure
  446. *
  447. * The name and name length are returned in the provided buffer space.
  448. *
  449. */
  450.  
  451. int CSK_UDPSocket::getsockname(void *name, int *namelen)
  452. {
  453.     if (fSocketState == SKk_STATE_NO_STREAM)
  454.         if (NewStream())
  455.             return -1;
  456.  
  457.     return CSK_INETSocket::getsockname(name, namelen);
  458. }
  459.  
  460.  
  461. /*************************************************************************** *
  462. * FUNCTION:
  463. *
  464. * CSK_UDPSocket::connect
  465. *
  466. * DESCRIPTION:
  467. *
  468. * Initiate a connection on a MacTCP socket.
  469. *
  470. * This  call specifies the address to  which  datagrams
  471. * are  to  be  sent, and the only address from which datagrams
  472. * are to be received.  
  473. *             
  474. * PARAMETERS:
  475. *
  476. * void *            -- The internet address to connect to
  477. * int                -- The length of the above internet address structure
  478. *
  479. * RETURNS:
  480. *
  481. * If the connection or binding succeeds, then 0 is returned.
  482. * Otherwise a -1 is returned, and a more specific error code
  483. * is stored in errno:
  484. *        
  485. *     EAFNOSUPPORT      The address family in addr is not AF_INET.
  486. *        
  487. *    EHOSTUNREACH      The TCP connection came up half-way and 
  488. *                     then failed.
  489. *
  490. * NOTES:
  491. *
  492. * UDP sockets may use connect() multiple times to change
  493. * their association. UDP sockets may dissolve the association
  494. * by connecting to an invalid address, such as a null
  495. * address.
  496. *
  497. */
  498.  
  499. int CSK_UDPSocket::connect(void * address, int addrlen)
  500. {
  501.     struct sockaddr_in *    addr    = (struct sockaddr_in *) address;
  502.         
  503.     if (addrlen != sizeof(struct sockaddr_in))
  504.         return SK_Error(EINVAL);
  505.  
  506.     if (addr->sin_family != AF_INET)
  507.         return SK_Error(EAFNOSUPPORT);
  508.     
  509.     /* make the stream if its not made already */
  510.     if (fSocketState == SKk_STATE_NO_STREAM) {
  511.         if (NewStream())
  512.             return -1;
  513.     } else if (fReceiveBuf)
  514.         if (FlushReadAhead())
  515.             return -1;
  516.     
  517.     /* record our peer */
  518.     fPeerSocketAddress.sin_len = sizeof(struct sockaddr_in);
  519.     fPeerSocketAddress.sin_addr.s_addr = addr->sin_addr.s_addr;
  520.     fPeerSocketAddress.sin_port = addr->sin_port;
  521.     fPeerSocketAddress.sin_family = AF_INET;
  522.     fSocketState = SKk_STATE_CONNECTED;
  523.     
  524.     return 0;
  525. }
  526.  
  527.  
  528. /*************************************************************************** *
  529. * FUNCTION:
  530. *
  531. * CSK_UDPSocket::recvfrom
  532. *
  533. * DESCRIPTION:
  534. *
  535. * recvfrom() attempts to receive a message (ie a datagram) on this socket
  536. *
  537. * PARAMETERS:
  538. *
  539. * void *        -- Pointer to buffer for returned bytes
  540. * int            -- Maximum number of bytes to read
  541. * int            -- unused
  542. * void *        -- Pointer to memory for return value (address of sender)
  543. * int *            -- Pointer to memory for length of return value
  544. *
  545. * RETURNS:
  546. *
  547. * int            -- Error return (0 = no error), -1 = error in which case
  548. *                   a more specific error code is stored in the global errno:
  549. *
  550. *    ESHUTDOWN    The socket has been shutdown for receive operations.
  551. *
  552. * The bytes received are read into the given buffer.
  553. *
  554. * The internet address of the caller and the length of that address
  555. * are placed into the last two parameters (void * and int).
  556. *
  557. * NOTES:
  558. *
  559. * Typically, read() is used with a TCP stream and recv() with
  560. * UDP where the idea of a message makes more sense. But in fact,
  561. * read() and recv() are equivalent.
  562. *
  563. * Regardless of non-blocking status, if less data is available
  564. * than has been requested, only that much data is returned.
  565. *
  566. * If the socket is marked for non-blocking I/O, and the socket
  567. * is empty, the operation will fail with the error EWOULDBLOCK.
  568. * Otherwise, the operation will block until data is available
  569. * or an error occurs.
  570. *
  571. * A return value of zero indicates that the stream has been
  572. * closed and all data has already been read. ie. end-of-file.
  573. *
  574. */
  575.  
  576.  
  577. int CSK_UDPSocket::recvfrom(void * buffer, int buflen, int, void * from, int * fromlen)
  578. {
  579.     /* make the stream if its not made already */
  580.     if (fSocketState == SKk_STATE_NO_STREAM)
  581.         if (NewStream())
  582.             return -1;
  583.             
  584.     /* dont block a non-blocking socket */
  585.     if (fNonBlocking && fLastAsyncErr == 1) 
  586.         return SK_Error(EWOULDBLOCK);
  587.     
  588.     SPIN(fLastAsyncErr == 1, SKk_DGRAM_READ,0);
  589.  
  590.     if (fLastAsyncErr!=noErr)
  591.         return SK_TCPError(fLastAsyncErr);
  592.  
  593.     /* return the data to the user - truncate the packet if necessary */
  594.     buflen = MIN(buflen,fBytesReceived);    
  595.     BlockMove(fReceiveBuf, buffer, buflen);
  596.  
  597.     if (from && *fromlen >= sizeof(struct sockaddr_in)) {
  598.         *(struct sockaddr_in *) from = fPeerSocketAddress;
  599.         *fromlen = sizeof (struct sockaddr_in);
  600.     }    
  601.     
  602.     /* continue the read-ahead - errors which occur */
  603.     /* here will show up next time around */
  604.     
  605.     FlushReadAhead();
  606.     ReadAhead();
  607.     
  608.     return buflen;
  609. }
  610.  
  611. /*************************************************************************** *
  612. * FUNCTION:
  613. *
  614. * CSK_UDPSocket::sendto
  615. *
  616. * DESCRIPTION:
  617. *
  618. * sendto() is used to transmit a message from this socket to another socket.
  619. *
  620. * PARAMETERS:
  621. *
  622. * void *        -- Pointer to buffer containing bytes to send
  623. * int            -- The number of bytes to send
  624. * int            -- Flags (???)
  625. * void *        -- Pointer to internet address to send to
  626. * int             -- Length of above internet address structure
  627. *
  628. * RETURNS:
  629. *
  630. * This call returns the number of bytes sent, or -1 if an error occurred,
  631. * in which case the global errno contains a more detailed error value:
  632. *
  633. *     EINVAL        The sum of the iov_len values in the iov array was
  634. *                greater than 65535 (TCP) or 65507 (UDP) or there
  635. *                were too many entries in the array (16 for TCP or
  636. *                6 for UDP).
  637. *
  638. *     ESHUTDOWN    The socket has been shutdown for send operations.
  639. *
  640. *     EMSGSIZE    The message is too big to send in one datagram. (UDP)
  641. *
  642. *     ENOBUFS        The transmit queue is full. (UDP)
  643. *
  644. * The bytes received are read into the given buffer.
  645. *
  646. * NOTES:
  647. *
  648. * Typically, write() is used with a TCP stream and send() with
  649. * UDP where the idea of a message makes more sense. But in fact,
  650. * write() and send() are equivalent.
  651. *
  652. * Write() and send() operations are not considered complete
  653. * until all data has been sent and acknowledged.
  654. *
  655. * The message must be short enough to fit into one datagram.
  656. *        
  657. * Buffer space must be available to hold the message to be 
  658. * transmitted, regardless of its non-blocking I/O state.
  659. *
  660. */
  661.  
  662. int CSK_UDPSocket::sendto(void * buffer, int count, int, void * to, int)
  663. {
  664.     SKt_MiniWds      awds;
  665.     OSErr        err;
  666.     UDPiopb *    pb;
  667.  
  668.     /* make the stream if its not made already */
  669.     if (fSocketState == SKk_STATE_NO_STREAM)
  670.         if (NewStream())
  671.             return -1;
  672.     
  673.     if (count > SKk_UDPMaxMessageSize)
  674.         return SK_Error(EMSGSIZE);
  675.         
  676.     awds.terminus = 0;
  677.     awds.length = count;
  678.     awds.ptr = (char *) buffer;
  679.     
  680.     // if no address passed, hope we have one already in fPeerSocketAddress field
  681.     if (to == NULL)
  682.         if (fPeerSocketAddress.sin_len)
  683.             to = &fPeerSocketAddress;
  684.         else
  685.             return SK_Error(EHOSTUNREACH);
  686.     
  687.     pb = GetPB();
  688.     pb->ioCompletion = UDPIOCompletionProc(udp_send_done);
  689.     pb->csCode = UDPWrite;
  690.     pb->csParam.send.remoteHost = ((struct sockaddr_in *)to)->sin_addr.s_addr;
  691.     pb->csParam.send.remotePort = ((struct sockaddr_in *)to)->sin_port;
  692.     pb->csParam.send.wdsPtr = (Ptr)&awds;
  693.     pb->csParam.send.checkSum = true;
  694.     pb->csParam.send.sendLength = 0 /* must be zero */;
  695.     
  696.     err = PBControlAsync(ParmBlkPtr(pb));
  697.  
  698.     if (err != 0)
  699.         return SK_TCPError(err);
  700.     
  701.     // get sneaky. compl. proc sets ptr to nil on completion, and puts result code in
  702.     // terminus field.
  703.     
  704.     SPIN(awds.ptr != NULL, SKk_DGRAM_WRITE, count);
  705.     
  706.     if (awds.terminus < 0)
  707.         return SK_TCPError(awds.terminus);
  708.     else
  709.         return count;
  710. }
  711.  
  712.  
  713. /*************************************************************************** *
  714. * FUNCTION:
  715. *
  716. * CSK_UDPSocket::select
  717. *
  718. * DESCRIPTION:
  719. *
  720. * Select read/write/exception abilities for this socket (???)
  721. *
  722. * PARAMETERS:
  723. *
  724. * Boolean *        -- Can read (???)
  725. * Boolean *     -- Can write (???)
  726. * Boolean *        -- Exception (???)
  727. *
  728. * RETURNS:
  729. *
  730. * int            -- ???
  731. *
  732. */
  733.  
  734. int CSK_UDPSocket::select(Boolean * canRead, Boolean * canWrite, Boolean * )
  735. {
  736.     int        goodies     =     0;
  737.  
  738.     if (canRead || canWrite)
  739.         if (fSocketState == SKk_STATE_NO_STREAM)
  740.             NewStream();
  741.                 
  742.     if (canRead)
  743.         if (fLastAsyncErr != 1) {
  744.             *canRead = true;
  745.             ++goodies;
  746.         }
  747.         
  748.     if (canWrite) {
  749.         *canWrite = true;
  750.         ++goodies;
  751.     }
  752.     
  753.     return goodies;
  754. }
  755.  
  756.  
  757.  
  758. /* end of SK_UCP.cc */
  759.  
  760.  
  761.